package org.itt.cp.gdc;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;

import javax.xml.parsers.FactoryConfigurationError;

import org.itt.schemas.gdc.DOCUMENTDocument;
import org.itt.schemas.ROOTDocument;
import org.itt.schemas.ROOTDocument.ROOT.DOCUMENTS;
import org.itt.schemas.ROOTDocument.ROOT.DOCUMENTS.DOCUMENT;
import org.itt.schemas.ROOTDocument.ROOT.DOCUMENTS.DOCUMENT.DOCUMENTPAGES;
import org.itt.schemas.ROOTDocument.ROOT.DOCUMENTS.DOCUMENT.DOCUMENTPAGES.PAGE;
import org.itt.schemas.ROOTDocument.ROOT.DOCUMENTS.DOCUMENT.INDEXFIELDS;
import org.itt.schemas.ROOTDocument.ROOT.DOCUMENTS.DOCUMENT.INDEXFIELDS.FIELD;
import org.itt.schemas.ROOTDocument.ROOT.INFO;
import org.itt.schemas.ROOTDocument.ROOT.INFO.HASHTYPE;
import org.apache.log4j.Logger;
import org.apache.xmlbeans.XmlOptions;
import org.itt.FooUtil;
import org.itt.Properties;
import org.itt.ap.Source;
import org.itt.ap.Writer;

public class GdCWriter implements Writer {
	int numOfIndexFiles = 0;
	int numOfXmlFiles = 0;

	private static Logger logger = Logger.getLogger("GdCWriter");

	@Override
	public byte[] files(Source source, String fileName) {
		byte[] fileByteArray = null;

		try {
			GdC gdc = (GdC) source;

			File file = new File(Properties.get().OUTPUT + "/" + fileName,
					Properties.get().OUTPUT_FILE_PREFIX + gdc.getId() + ".xml");

			if (!file.exists()) {
				file.getParentFile().mkdirs();
			}

			DOCUMENTDocument doc = DOCUMENTDocument.Factory.newInstance();
			DOCUMENTDocument.DOCUMENT document = doc.addNewDOCUMENT();

			document.setRECORDTIME(new SimpleDateFormat("dd/MM/yyyy HH:mm:ss")
					.format(gdc.getRecordTime()));
			document.setFISCALCODE(gdc.getCallerFiscalcode());
			document.setSERVICENS(gdc.getServiceNS());
			document.setOPERATION(gdc.getOperation());
			document.setCOMPRESSEDDOC(gdc.getCompressedDoc());

			XmlOptions opts = new XmlOptions();

			opts.setUseDefaultNamespace();
			opts.setSaveOuter();
			opts.setSavePrettyPrint();
			opts.setCharacterEncoding("iso-8859-1");
			document.save(file, opts);

			fileByteArray = Files
					.readAllBytes(Paths.get(file.getAbsolutePath()));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return fileByteArray;
	}

	@SuppressWarnings("resource")
	@Override
	public void index(Source source) {
		int index = 1;
		String indexFileName = null;
		int mapSize, maxBatchSize = 0;
		int extIteration = 1;

		int year = Calendar.getInstance().get(Calendar.YEAR);
		int month = Calendar.getInstance().get(Calendar.MONTH) + 1;
		int day = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);

		logger.info("Inizio il processo di scrittura");

		TreeMap<Integer, Source> map = source.getMap();

		mapSize = map.size();

		try {
			maxBatchSize = Integer.valueOf(Properties.get().MAX_BATCH_SIZE);
		} catch (NumberFormatException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		Set<Entry<Integer, Source>> entrySet = map.entrySet();

		Iterator<Entry<Integer, Source>> iterator = entrySet.iterator();

		logger.debug("Memorizzo l'istante d'inizio elaborazione");
		long start = System.nanoTime();

		while (mapSize > 0) {
			try {
				Integer customerId = Integer
						.valueOf(Properties.get().INDEX_CUSTOMER_ID);

				customerId += extIteration - 1;

				String dateSuffix = "_" + year + month + day + "_";

				indexFileName = "GDC" + "_" + customerId + dateSuffix
						+ extIteration;

				File ctrlFile = new File(Properties.get().OUTPUT, indexFileName
						+ ".ctrl");

				if (!ctrlFile.exists()) {
					ctrlFile.getParentFile().mkdirs();
				}

				new FileOutputStream(ctrlFile, false);

				File indexFile = new File(Properties.get().OUTPUT,
						indexFileName + ".xml");

				if (!indexFile.exists()) {
					indexFile.getParentFile().mkdirs();
				}

				logger.info("Inizio a costruire il contenuto del file di indice XML");
				ROOTDocument doc = ROOTDocument.Factory.newInstance();
				logger.debug("<ROOT>");
				ROOTDocument.ROOT root = doc.addNewROOT();

				logger.debug("\t<INFO>");
				INFO info = root.addNewINFO();

				logger.debug("\t\t<LOADDOCUMENTPATH>");
				info.setLOADDOCUMENTPATH(indexFileName);

				logger.debug("\t\t<CUSTOMERID>");
				info.setCUSTOMERID(customerId);

				logger.debug("\t\t<INDEX_PIVA_COD_FISC>");
				info.setPIVACODFISC(Properties.get().INDEX_PIVA_COD_FISC);

				logger.debug("\t\t<INDEX_MAP_ID>");
				info.setMAPID(Byte.valueOf(Properties.get().INDEX_MAP_ID));

				logger.debug("\t\t<COURIERNAME>");
				info.setCOURIERNAME(indexFileName);

				logger.debug("\t\t<INDEX_SIGN_SINGLEDOC>");
				info.setSIGNSINGLEDOC(Properties.get().INDEX_SIGN_SINGLEDOC);

				logger.debug("\t\t<HASHTYPE>");
				HASHTYPE hashType = info.addNewHASHTYPE();

				hashType.setCODE(Properties.get().INDEX_HASH_TYPE_CODE);
				hashType.setStringValue(Properties.get().INDEX_HASH_TYPE);

				logger.debug("\t<DOCUMENTS>");
				DOCUMENTS documents = root.addNewDOCUMENTS();

				logger.debug("\t\t<FAMILY>");
				documents
						.setFAMILY(Integer.valueOf(Properties.get().INDEX_FAMILY_ID));

				while (iterator.hasNext()) {
					Entry<Integer, Source> m = iterator.next();

					GdC gdc = (GdC) m.getValue();

					logger.debug("\t\t<DOCUMENT>");
					DOCUMENT document = documents.addNewDOCUMENT();

					logger.debug("\t\t\t<OPTYPE>");
					document.setOPTYPE("INPUT");

					logger.debug("\t\t\t<DOCDATE>");
					document.setDOCDATE(new SimpleDateFormat("dd/MM/yyyy")
							.format(gdc.getRecordTime()));

					logger.debug("\t\t\t<INDEXFIELDS>");
					INDEXFIELDS indexFields = document.addNewINDEXFIELDS();

					FIELD NOME_FILE = indexFields.addNewFIELD();
					NOME_FILE.setNAME("NOME_FILE");
					NOME_FILE.setVALUE(Properties.get().OUTPUT_FILE_PREFIX
							+ gdc.getId() + ".xml");

					logger.debug("\t\t\t<A>");
					FIELD A = indexFields.addNewFIELD();
					A.setNAME("A");
					A.setVALUE(String.valueOf(gdc.getId()));

					logger.debug("\t\t\t<B>");
					FIELD B = indexFields.addNewFIELD();
					B.setNAME("B");
					B.setVALUE(new SimpleDateFormat("dd/MM/yyyy HH:mm:ss")
							.format(gdc.getRecordTime()));

					logger.debug("\t\t\t<C>");
					FIELD C = indexFields.addNewFIELD();
					C.setNAME("C");
					C.setVALUE(gdc.getCallerId());

					logger.debug("\t\t\t<D>");
					FIELD D = indexFields.addNewFIELD();
					D.setNAME("D");
					D.setVALUE(gdc.getCallerName());

					logger.debug("\t\t\t<E>");
					FIELD E = indexFields.addNewFIELD();
					E.setNAME("E");
					E.setVALUE(gdc.getCallerSurname());

					logger.debug("\t\t\t<F>");
					FIELD F = indexFields.addNewFIELD();
					F.setNAME("F");
					F.setVALUE(gdc.getCallerCountry());

					logger.debug("\t\t\t<G>");
					FIELD G = indexFields.addNewFIELD();
					G.setNAME("G");
					G.setVALUE(gdc.getCallerFiscalcode());

					logger.debug("\t\t\t<H>");
					FIELD H = indexFields.addNewFIELD();
					H.setNAME("H");
					H.setVALUE(gdc.getDomain());

					logger.debug("\t\t\t<I>");
					FIELD I = indexFields.addNewFIELD();
					I.setNAME("I");
					I.setVALUE(gdc.getServiceNS());

					logger.debug("\t\t\t<J>");
					FIELD J = indexFields.addNewFIELD();
					J.setNAME("J");
					J.setVALUE(gdc.getOperation());

					logger.debug("\t\t\t<K>");
					FIELD K = indexFields.addNewFIELD();
					K.setNAME("K");
					K.setVALUE(String.valueOf(gdc.isResult()));

					logger.debug("\t\t\t<DOCUMENTPAGES>");
					DOCUMENTPAGES documentPages = document
							.addNewDOCUMENTPAGES();

					logger.debug("\t\t\t\t<PAGE>");
					PAGE page = documentPages.addNewPAGE();
					page.setHASH(FooUtil
							.calculateHash(files(gdc, indexFileName)));
					page.setStringValue(Properties.get().OUTPUT_FILE_PREFIX
							+ gdc.getId() + ".xml");

					if ((index / maxBatchSize + 1) > extIteration) {
						iterator.remove();
						index++;
						mapSize--;

						extIteration++;

						break;
					}

					iterator.remove();
					index++;
					mapSize--;
				}

				XmlOptions opts = new XmlOptions();
				opts.setCharacterEncoding("iso-8859-1");
				opts.setUseDefaultNamespace();

				opts.setSavePrettyPrint();
				opts.setCompileNoAnnotations();

				doc.save(indexFile, opts);

				numOfIndexFiles++;
			} catch (FactoryConfigurationError | IOException e) {
				logger.error(e);
				System.exit(1);
			}

			if (mapSize == 0) {
				logger.info("Durata creazione output: "
						+ FooUtil.prettyPrintTime(System.nanoTime() - start));

				logger.info("Elaborazione terminata con successo");
				System.exit(0);
			}
		}
	}

	@Override
	public void createZip(File file, String[] objects) {
		// TODO Auto-generated method stub
	}
}